/* verilator lint_off UNUSEDSIGNAL */
`include "defines.svh"
`default_nettype wire

module EXE_STAGE(
    input clk,
    input reset,
    input logic id_valid,
    output logic exe_ready,
    output logic exe_valid,
    input logic mem_ready, 
    input id_to_exe_bus_t id_to_exe_bus,
    output exe_to_mem_bus_t exe_to_mem_bus,
    output exe_to_id_bypass_t exe_to_id_bypass,
    output exe_to_front_bypass_t exe_to_front_bypass,
    input wb_to_front_bypass_t wb_to_front_bypass,

    // sram
    output word_t data_sram_pc,
    output data_sram_en,
    output word_t data_sram_addr,
    output logic data_sram_wen,
    output logic [3:0] data_sram_mask,
    output word_t data_sram_wdata,
    input logic axi_data_flushreq
);
id_to_exe_bus_t id_to_exe_bus_r;

// assign stallreq_csr_from_exe = id_to_exe_bus_r.sel_exception == `EXC_ON;
// assign ecallreq_from_exe = id_to_exe_bus_r.sel_exception == `EXC_EC;

logic ecall_en;
logic de_shake,em_shake,stall_exe,flush_exe;
assign de_shake = id_valid & exe_ready;
assign em_shake = mem_ready & exe_valid;
assign stall_exe = axi_data_flushreq;
assign flush_exe = wb_to_front_bypass.ecall_en | ecall_en;
always_ff @(posedge clk) begin
    if(reset) begin
        exe_valid <= `OFF;
    end else begin
        exe_valid <= de_shake;
    end
end
assign exe_ready = mem_ready;

// 接收
always_ff @(posedge clk) begin
    if(reset) begin
        id_to_exe_bus_r <= `NULL;
    end else if (de_shake & ~stall_exe & ~flush_exe) begin
        id_to_exe_bus_r <= id_to_exe_bus;
    end else if(flush_exe & ~stall_exe) begin
        id_to_exe_bus_r <= `NULL;
    end
end


// 发送
always_comb begin
    if(reset) begin
        exe_to_mem_bus = `NULL;
    end else begin
        exe_to_mem_bus = '{
            exe_pc,
            id_to_exe_bus_r.debug_dnpc,
            exe_inst,
            load_en & exe_valid,
            store_en & exe_valid,
            alu_result,
            id_to_exe_bus_r.store_data,
            id_to_exe_bus_r.sel_mask,

            id_to_exe_bus_r.rfw & exe_valid,
            id_to_exe_bus_r.rf_waddr,
            id_to_exe_bus_r.sel_rf_wdata,

            id_to_exe_bus_r.sel_exception,
            id_to_exe_bus_r.rfc_waddr,
            id_to_exe_bus_r.alu_src2
        };
    end
end


word_t exe_pc,exe_inst;
word_t alu_result;//作为load/store的addr，也可作为rf写入的data
logic load_en,store_en;
always_comb begin
    if(reset == `ON) begin 
        load_en = `OFF;
        store_en = `OFF;
        exe_pc = `NULL;
        exe_inst = `NULL;
        data_sram_en = `OFF;
        data_sram_wen = `OFF;
        data_sram_mask = `NULL;
        data_sram_addr = `NULL;
        data_sram_wdata = `NULL;
        data_sram_pc = `NULL;
    end else begin
        load_en = id_to_exe_bus_r.dse & ~id_to_exe_bus_r.dsw & exe_valid;
        store_en = id_to_exe_bus_r.dse &  id_to_exe_bus_r.dsw & exe_valid;
        {exe_pc,exe_inst} = {id_to_exe_bus_r.pc,id_to_exe_bus_r.inst};
        data_sram_pc = exe_pc;
        data_sram_en = load_en | store_en;
        data_sram_wen = store_en;
        data_sram_addr = alu_result;
        case(id_to_exe_bus_r.sel_mask)
            `M_W: begin 
                data_sram_mask = 4'b1111;
            end
            `M_B: begin
                data_sram_mask = 4'b0001;
            end
            `M_H: begin
                data_sram_mask = 4'b0011;
            end
            `M_LBU: begin
                data_sram_mask = 4'b0001;
            end
            `M_LHU: begin
                data_sram_mask = 4'b0011;
            end
            default: begin
                data_sram_mask = 4'b0000;
            end
        endcase
        data_sram_wdata = id_to_exe_bus_r.store_data;
    end
end
assign ecall_en = (id_to_exe_bus_r.sel_exception == `EXC_EC) & exe_valid;

Alu alu1(
    .clock(clk),
    .reset(reset),
    .io_aluSrc1(id_to_exe_bus_r.alu_src1),
    .io_aluSrc2(id_to_exe_bus_r.alu_src2),
    .io_aluOp(id_to_exe_bus_r.sel_alu_op),
    .io_aluResult(alu_result)
);



assign exe_to_id_bypass='{
    id_to_exe_bus_r.rfw & exe_valid,
    id_to_exe_bus_r.rf_waddr,
    alu_result
};

assign exe_to_front_bypass = '{
    load_en & exe_valid,
    store_en & exe_valid,
    ecall_en
};


endmodule
